#include "derivadores.h"




/**
@function
@name DerivarVariable
@author Emiliano Parizzi
@param origen: const TAB*
@param destino: TAB*
@return int
@description Deriva el corriente del origen, que tiene que ser una variable y la guarda en destino
*/
int DerivarVariable(const TAB* origen, TAB* destino)
{
    TLiteral constante;
    int error;

    Literal_Crear(&constante, "1", "x"); /* Creo el literal 1 */
    AB_Insertar(destino, RAIZ, &constante, &error); /* Inserto el 1 en la raiz del destino */

    return RES_OK;
}
/**
@function
@name DerivarConstante
@author Emiliano Parizzi
@param origen: const TAB*
@param destino: TAB*
@return int
@description Deriva el corriente del origen, que tiene que ser una constante y la guarda en destino
*/
int DerivarConstante(const TAB* origen, TAB* destino)
{
    TLiteral constante;
    int error;

    Literal_Crear(&constante, "0", "x"); /* Creo el literal 0 */
    AB_Insertar(destino, RAIZ, &constante, &error); /* Inserto el 0 en la raiz del destino */

    return RES_OK;
}

int DerivarSumaResta(const TAB* origen, TAB* destino)
{
    TAB resder,resizq,origencpy;
    TLiteral operador;
    int error;

    memcpy(&origencpy,origen, sizeof(origencpy)); /*copio origen*/

    AB_Crear(&resder,sizeof(TLiteral)); /*creo el arbol con el resultado de la der*/
    AB_Crear(&resizq,sizeof(TLiteral));/*creo el arbol con el resultado de la izq*/

    AB_ElemCte(origencpy,&operador); /*obtengo el "+" o "-" */
    AB_Insertar(destino,RAIZ,&operador,&error);/*inserto el "+" o "-" en la raiz del arbol*/
    Literal_Destruir(&operador);

    AB_MoverCte(&origencpy,DER,&error); /*muevo a la derecha el cte de la copia*/
    AB_ElemCte(origencpy,&operador); /*obtengo el cte*/
    Literal_Derivar(&operador,&origencpy,&resder); /*derivo el subarbol derecho*/



    AB_MoverCte(&origencpy,PAD,&error);/*vuelvo a "+" o "-" */
    AB_MoverCte(&origencpy,IZQ,&error);/*muevo a la IZQ*/
    AB_ElemCte(origencpy,&operador);/*vuelvo a obtener el operador*/
    Literal_Derivar(&operador,&origencpy,&resizq); /*derivo subarbol izq*/



    AB_PegarSubarbol(&resder,destino,DER); /*pego el subarbol der*/
    AB_PegarSubarbol(&resizq,destino,IZQ); /*pego el subarbol izq*/

    BorrarLiteral(resder,RAIZ);
    BorrarLiteral(resizq,RAIZ);
    AB_Vaciar(&resder);
    AB_Vaciar(&resizq);
    Literal_Destruir(&operador);


    /**     ESQUEMA ARBOL con variables

              operador
               /    \
           resizq    resder


   */


    return RES_OK;
}

int DerivarSuma(const TAB* origen, TAB* destino)
{
    return DerivarSumaResta(origen, destino);
}

int DerivarResta(const TAB* origen, TAB* destino)
{
    return DerivarSumaResta(origen, destino);
}

int DerivarProducto(const TAB* origen, TAB* destino)
{
    /**
        Esquema de derivada del producto de F por G

             *
           /   \        -->
         F      G                   +
                                  /  \
                                *      *
                              /  \    / \
                             F'   G  F   G'

    */
    int error;
    TAB origenCpy, F, G, F_Prima, G_Prima;
    TLiteral litAux;
    char* var = "x";

    /* Hago una copia del origen para mantener el const */
    memcpy(&origenCpy, origen, sizeof(origenCpy));

    /* Creo los arboles auxiliares F, G, F_Prima y G_Prima */
    AB_Crear(&F, sizeof(TLiteral));
    AB_Crear(&G, sizeof(TLiteral));
    AB_Crear(&F_Prima, sizeof(TLiteral));
    AB_Crear(&G_Prima, sizeof(TLiteral));

    /**** Obtengo F, G, F' y G' ****/
    /* Obtengo F y derivo obteniendo F' */
    AB_CopiarSubarbol(&origenCpy, &F, IZQ);
    /*printf("\nF: "); inorder(F, RAIZ);*/
    AB_MoverCte(&F, RAIZ, &error); if(error != 0) return error;
    AB_ElemCte(F, &litAux);
    Literal_Derivar(&litAux, &F, &F_Prima);
    /*printf("\nF': "); inorder(F_Prima, RAIZ);*/
    /* Obtengo G y derivo obteniendo G' */
    AB_CopiarSubarbol(&origenCpy, &G, DER);
    /*printf("\nG': "); inorder(G, RAIZ);*/
    AB_MoverCte(&G, RAIZ, &error); if(error != 0) return error;
    AB_ElemCte(G, &litAux);
    Literal_Derivar(&litAux, &G, &G_Prima);
    /*printf("\nG': "); inorder(G_Prima, RAIZ);*/

    /** Empiezo a armar la estructura de la derivada en destino  */
     /* Inserto la raiz (+) en el destino */
    Literal_Crear(&litAux, "+", var);
    AB_Insertar(destino, RAIZ, &litAux, &error); if(error != 0) return error;
    /* Creo el primer literal de la multiplicacion */
    Literal_Crear(&litAux, "*", var);
    /* Lo inserto en el izquierdo del corriente del destino */
    AB_Insertar(destino, IZQ, &litAux, &error); if(error != 0) return error;
    /* Pego F' en el izquierdo del corriente */
    if(AB_PegarSubarbol(&F_Prima, destino, IZQ) == 0) return ERROR;
    /* Pego G en el derecho del corriente */
    if(AB_PegarSubarbol(&G, destino, DER) == 0) return ERROR;

    /* Destino: Vuelvo a la suma (+) moviendome a la raiz*/
    AB_MoverCte(destino, RAIZ, &error); if(error != 0) return error;
    /* Creo el segundo literal de la multiplicacion */
    Literal_Crear(&litAux, "*", var);
    /* Lo inserto en el derecho del corriente del destino */
    AB_Insertar(destino, DER, &litAux, &error); if(error != 0) return error;
    /* Pego F en el izquierdo del corriente */
    if(AB_PegarSubarbol(&F, destino, IZQ) == 0) return -1;
    /* Pego G' en el derecho del corriente */
    if(AB_PegarSubarbol(&G_Prima, destino, DER) == 0) return -1;

    /*printf("\nDestino': "); inorder(*destino, RAIZ);*/

    /* Destruyo los arboles auxiliares */
    AB_Vaciar(&F);
    AB_Vaciar(&G);
    AB_Vaciar(&F_Prima);
    AB_Vaciar(&G_Prima);

    return RES_OK;
}

/**
@function
@name DerivarConstante
@author Emiliano Parizzi
@param origen: const TAB*
@param destino: const TAB*
@return int
@description Deriva el corriente del origen, que tiene que ser una division y la guarda en destino
*/
int DerivarDivision(const TAB* origen, TAB* destino)
{
    /**
        Esquema de derivada de la division de F por G

            DIV                         DIV
           /   \        -->           /     \
         F      G                   -        ^
                                  /  \      / \
                                *      *   G   2
                              /  \    / \
                             F'   G  F   G'

    */
    int error;
    TAB origenCpy, F, G, F_Prima, G_Prima;
    TLiteral litAux;
    char* var = "x";

    /* Hago una copia del origen para mantener el const */
    memcpy(&origenCpy, origen, sizeof(origenCpy));

    /* Creo los arboles auxiliares F, G, F_Prima y G_Prima */
    AB_Crear(&F, sizeof(TLiteral));
    AB_Crear(&G, sizeof(TLiteral));
    AB_Crear(&F_Prima, sizeof(TLiteral));
    AB_Crear(&G_Prima, sizeof(TLiteral));

    /* Inserto la raiz (/) en el destino */
    AB_ElemCte(origenCpy, &litAux);
    AB_Insertar(destino, RAIZ, &litAux, &error); if(error != 0) return error;

    /**** Obtengo F, G, F' y G' ****/
    /* Obtengo F y derivo obteniendo F' */
    AB_CopiarSubarbol(&origenCpy, &F, IZQ);
    /*printf("\nF: "); inorder(F, RAIZ);*/
    AB_MoverCte(&F, RAIZ, &error); if(error != 0) return error;
    AB_ElemCte(F, &litAux);
    Literal_Derivar(&litAux, &F, &F_Prima);
    /*printf("\nF': "); inorder(F_Prima, RAIZ);*/
    /* Obtengo G y derivo obteniendo G' */
    AB_CopiarSubarbol(&origenCpy, &G, DER);
    /*printf("\nG': "); inorder(G, RAIZ);*/
    AB_MoverCte(&G, RAIZ, &error); if(error != 0) return error;
    AB_ElemCte(G, &litAux);
    Literal_Derivar(&litAux, &G, &G_Prima);
    /*printf("\nG': "); inorder(G_Prima, RAIZ);*/

    /** Empiezo a armar la estructura de la derivada en destino  */
    /* Primero la parte izquierda. Creo el literal resta */
    Literal_Crear(&litAux, "-", var);
    /* Lo inserto en el izquierdo del corriente del destino */
    AB_Insertar(destino, IZQ, &litAux, &error); if(error != 0) return error;
    /* Creo el primer literal de la multiplicacion */
    Literal_Crear(&litAux, "*", var);
    /* Lo inserto en el izquierdo del corriente del destino */
    AB_Insertar(destino, IZQ, &litAux, &error); if(error != 0) return error;
    /* Pego F' en el izquierdo del corriente */
    if(AB_PegarSubarbol(&F_Prima, destino, IZQ) == 0) return ERROR;
    /* Pego G en el derecho del corriente */
    if(AB_PegarSubarbol(&G, destino, DER) == 0) return ERROR;

    /* Destino: Vuelvo a la resta (-) moviendome al padre*/
    AB_MoverCte(destino, PAD, &error); if(error != 0) return error;
    /* Creo el segundo literal de la multiplicacion */
    Literal_Crear(&litAux, "*", var);
    /* Lo inserto en el derecho del corriente del destino */
    AB_Insertar(destino, DER, &litAux, &error); if(error != 0) return error;
    /* Pego F en el izquierdo del corriente */
    if(AB_PegarSubarbol(&F, destino, IZQ) == 0) return -1;
    /* Pego G' en el derecho del corriente */
    if(AB_PegarSubarbol(&G_Prima, destino, DER) == 0) return -1;

    /* Vuelvo a la raiz (/) de destino para armar la parte derecha */
    AB_MoverCte(destino, RAIZ, &error); if(error != 0) return error;
    /* Creo el literal de la potencia para la parte derecha de la derivada */
    Literal_Crear(&litAux, "^", var);
    /* Lo inserto como derecho en el destino */
    AB_Insertar(destino, DER, &litAux, &error); if(error != 0) return error;
    /* Pego G en el izquierdo del corriente */
    if(AB_PegarSubarbol(&G, destino, IZQ) == 0) return -1;
    /* Creo el literal "2" para la potencia cuadrada */
    Literal_Crear(&litAux, "2", var);
    /* Lo inserto a la derecha */
    AB_Insertar(destino, DER, &litAux, &error); if(error != 0) return error;

    /*printf("\nDestino': "); inorder(*destino, RAIZ);*/

    /* Destruyo los arboles auxiliares */
    AB_Vaciar(&F);
    AB_Vaciar(&G);
    AB_Vaciar(&F_Prima);
    AB_Vaciar(&G_Prima);

    return RES_OK;
}
int DerivarPotencia(const TAB* origen, TAB* destino)
{
    TAB resizq,origencpy,ramaizq;
    TLiteral exponente,por,circunflejo,cte,expmenos;
    int error,enc,valor,i;
    char* exp;
    char val[10];


    memcpy(&origencpy,origen, sizeof(origencpy));
    AB_Crear(&resizq,sizeof(TLiteral)); /*creo el arbol con el resultado de la der*/

    AB_ElemCte(origencpy,&circunflejo); /*ontengo el "^"*/


    AB_CopiarSubarbol(&origencpy,&ramaizq,IZQ); /*copio el arbol la rama IZQ*/

    AB_ElemCte(ramaizq,&cte); /*obtengo elemento corriente*/
    Literal_Derivar(&cte,&ramaizq,&resizq); /*derivo arbol izq*/



    enc=0;

    Literal_Crear(&por,"*","x"); /*creo un literal "*" */
    AB_MoverCte(&origencpy,DER,&error);/*muevo el corriente a la DER*/
    AB_ElemCte(origencpy,&exponente);/* copio el EXPONENTE de la potencia*/
    Literal_AString(&exponente, &exp);/*lo paso a string*/
    valor=atoi(exp);/*lo transformo a int*/
    valor--;/*le disminuyo un valor*/

    i = sprintf(val, "%d", valor);


    Literal_Crear(&expmenos,val,"x");/*lo creo como litera*/




    AB_Insertar(destino,RAIZ,&por,&error);/*inserto "*" en la raiz*/
    AB_PegarSubarbol(&resizq,destino,IZQ);/*pego la rama izq derivada a la izq*/
    AB_Insertar(destino,DER,&por,&error);/*inserto "*" a la der*/
    AB_Insertar(destino,IZQ,&exponente,&error); /*inserto el exponente a la izq*/
    AB_MoverCte(destino,PAD,&error);
    AB_Insertar(destino,DER,&circunflejo,&error);/*inserto el "^" a la izq*/
    AB_PegarSubarbol(&ramaizq,destino,IZQ);/*pego la ramaizq sin derivar a la IZQ*/

    /*inorden(*destino,RAIZ);-----------------------------------------------------------------*/

    AB_Insertar(destino,DER,&expmenos,&error);/*pego el expmenos a la der*/
    AB_MoverCte(destino,RAIZ,&error);

    BorrarLiteral(resizq,RAIZ);
    BorrarLiteral(ramaizq,RAIZ);
    AB_Vaciar(&resizq);
    AB_Vaciar(&ramaizq);
    Literal_Destruir(&exponente);
    Literal_Destruir(&por);
    Literal_Destruir(&circunflejo);
    Literal_Destruir(&cte);
    Literal_Destruir(&expmenos);
    free(exp);



    /**     ESQUEMA ARBOL con variables

                por
               /    \
           resizq    por
                     / \
            exponente    circunflejo
                        /  \
                  ramaizq    expmenos

   */





    return RES_OK;
}
  int DerivarSeno(const TAB* origen, TAB* destino) {
    TAB resder,ramader,origencpy;

    TLiteral coseno,por,seno,opaux;
    int error;
    char* var;

    memcpy(&origencpy,origen, sizeof(origencpy)); /*copio origen*/

    AB_Crear(&resder,sizeof(TLiteral)); /*creo el arbol con el resultado de la der*/
    AB_Crear(&ramader,sizeof(TLiteral)); /*creo el arbol con la rama der*/

    Literal_Crear(&coseno,"cos",var);
    Literal_Crear(&por,"*",var);
    AB_ElemCte(origencpy,&seno); /*obtengo el "sin"*/

    AB_Insertar(destino,RAIZ,&por,&error); /*inserto el "*" en la raiz del arbol*/

    AB_CopiarSubarbol(&origencpy,&ramader,DER);

    AB_MoverCte(&origencpy,DER,&error); /*muevo a la derecha el cte de la copia*/
    AB_ElemCte(origencpy,&opaux); /* Obtengo el operador auxiliar*/




    Literal_Derivar(&opaux,&origencpy,&resder); /*derivo subarbol DER*/

    AB_PegarSubarbol(&resder,destino,IZQ); /* pego el sub-arbol derivado */
    AB_Insertar(destino,DER,&coseno,&error); /* inserto perador "cos" */
    AB_MoverCte(destino,DER,&error); /* me muevo a la derecha */
    AB_PegarSubarbol(&ramader,destino,DER); /* pego el sub-arbol sin derivar  */

    BorrarLiteral(ramader,RAIZ);
    BorrarLiteral(resder,RAIZ);
    AB_Vaciar(&resder);
    AB_Vaciar(&ramader);



    /**
                *
           /         \
        RESDER       COS
                       \
                        RAMADER



    */



    return RES_OK;
    }

int DerivarCoseno(const TAB* origen, TAB* destino) {
    /**
         cos                              *
            \                        /         \
             F                      F'           -
					                           /	\
						                      0     Sin
						                              \
							                           F
   */
    int error;
    TAB origenCpy, F, F_Prima;
    TLiteral litAux;


    /* Hago una copia del origen para mantener el const */
    memcpy(&origenCpy, origen, sizeof(origenCpy));

    /* Creo los arboles auxiliares F, G, F_Prima y G_Prima */
    AB_Crear(&F, sizeof(TLiteral));
    AB_Crear(&F_Prima, sizeof(TLiteral));

    /* Inserto la raiz (*) en el destino */
    Literal_Crear(&litAux,"*", "x");
    AB_Insertar(destino, RAIZ, &litAux, &error); if(error != 0) return error;

    /**** Obtengo F y F' ****/
    /* Obtengo F y derivo obteniendo F' */
    AB_CopiarSubarbol(&origenCpy, &F, DER);
    /*printf("\nF: "); inorder(F, RAIZ);*/
    AB_MoverCte(&F, RAIZ, &error); if(error != 0) return error;
    AB_ElemCte(F, &litAux);
    Literal_Derivar(&litAux, &F, &F_Prima);
    /*printf("\nF': "); inorder(F_Prima, RAIZ);*/

    /* Pego F' en el izquierdo del corriente */
    if(AB_PegarSubarbol(&F_Prima, destino, IZQ) == 0) return ERROR;

    /* Inserto a la derecha del corriente (-) en el destino */
    Literal_Crear(&litAux,"-", "x");
    AB_Insertar(destino, DER, &litAux, &error); if(error != 0) return error;

    /* Inserto 0 a la izquierda del corriente (-) en el destino */
    Literal_Crear(&litAux,"0", "x");
    AB_Insertar(destino, IZQ, &litAux, &error); if(error != 0) return error;

    /* Me muevo al padre */
    AB_MoverCte(destino, PAD, &error);if(error != 0) return error;

    /* Inserto sin a la derecha del corriente (-) en el destino */
    Literal_Crear(&litAux,"sin", "x");
    AB_Insertar(destino, DER, &litAux, &error); if(error != 0) return error;

    /* Pego F en el derecho del corriente */
    if(AB_PegarSubarbol(&F, destino, DER) == 0) return ERROR;

    /* Destruyo los arboles auxiliares */
    AB_Vaciar(&F);
    AB_Vaciar(&F_Prima);

	return RES_OK;
}

/**
@function
@name DerivarLogaritmo
@author Emiliano Parizzi
@param origen: const TAB*
@param destino: TAB*
@return int
@description Deriva el corriente del origen, que tiene que ser un logaritmo natural y la guarda en destino
*/
int DerivarLogaritmo(const TAB* origen, TAB* destino)
{
    /**
        Esquema
        -------

        Origen:
        ln
          \
           F

        Destino:
          DIV
          / \
        F'   F

    */

    int error;
    TAB origenCpy, F, F_Prima;
    TLiteral litAux;
    char* var = "x";

    /* Hago una copia del origen para mantener el const */
    memcpy(&origenCpy, origen, sizeof(origenCpy));

    /* Creo los arboles auxiliares F y F_Prima */
    AB_Crear(&F, sizeof(TLiteral));
    AB_Crear(&F_Prima, sizeof(TLiteral));

    /* Inserto la raiz (/) en el destino */
    Literal_Crear(&litAux, "/", var);
    AB_Insertar(destino, RAIZ, &litAux, &error); if(error != 0) return error;

    /* Origen: Obtengo F y derivo obteniendo F' */
    AB_CopiarSubarbol(&origenCpy, &F, DER);
    /*printf("\nF: "); inorder(F, RAIZ);*/
    AB_MoverCte(&F, RAIZ, &error); if(error != 0) return error;
    AB_ElemCte(F, &litAux);
    Literal_Derivar(&litAux, &F, &F_Prima);
    /*printf("\nF': "); inorder(F_Prima, RAIZ);*/

    /* Pego F y F' en el destino */
    if(AB_PegarSubarbol(&F_Prima, destino, IZQ) == 0) return ERROR;
    if(AB_PegarSubarbol(&F, destino, DER) == 0) return ERROR;

    /* Vacio los arboles auxiliares */
    AB_Vaciar(&F);
    AB_Vaciar(&F_Prima);

    return RES_OK;
}

